/**
 * @Description:
 * @Author bianpengfei
 * @create 2022/9/22 17:23
 */
const path = require('path')
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
const os = require('os')

const ROOT_PATH = path.resolve(__dirname, '../') // 根目录路径
const SRC_PATH = path.resolve(__dirname, '../src') // 根目录路径
const IS_PRO = process.env.NODE_ENV === 'production' // 是否是生产环境
const IS_DEV = process.env.NODE_ENV === 'development' // 是否是开发环境

/**
 * 获取处理样式的loaders
 * @param loader
 * @param options
 * @param resourceOptions
 * @returns {(string|string|string|{loader: string, options: {postcssOptions: {plugins: string[]}}})[]}
 */
const getStyleLoaders = (loader, options = {}, resourceOptions) => {
  const styleLoader = IS_PRO ? MiniCssExtractPlugin.loader : 'vue-style-loader'

  const preLoader = loader && {
    loader: ~loader.indexOf('loader') ? loader : `${loader}-loader`,
    options: {
      ...options
    }
  }

  const sassResourcesLoader = loader &&
    resourceOptions && {
      loader: 'sass-resources-loader',
      options: {
        ...resourceOptions
      }
    }

  return [
    styleLoader,
    'css-loader',
    {
      loader: 'postcss-loader',
      options: {
        postcssOptions: {
          plugins: [
            'postcss-preset-env',
            'autoprefixer',
            [
              'postcss-pxtorem',
              {
                rootValue: 50,
                minPixelValue: 2,
                propWhiteList: [],

                unitPrecision: 3, //允许REM单位增长到的十进制数字,小数点后保留的位数。
                // propList: [],
                exclude: /(node_module)/i, //默认false，可以（reg）利用正则表达式排除某些文件夹的方法，例如/(node_module)/ 。如果想把前端UI框架内的px也转换成rem，请把此属性设为默认值
                selectorBlackList: ['.van', '.page-example'], //要忽略并保留为px的选择器，本项目我是用的vant ui框架，所以忽略他
                mediaQuery: false //（布尔值）允许在媒体查询中转换px。
              }
            ]
          ]
        }
      }
    },
    preLoader,
    sassResourcesLoader
  ].filter(Boolean)
}

/**
 * 生成多个预处理css loader oneOf
 * @param loader
 * @param options
 * @param resourceOptions
 * @returns {[{resourceQuery: RegExp, use: (string|{loader: string, options: {localIdentName: string, modules: boolean}}|{loader: string, options: {postcssOptions: {plugins: string[]}}}|{loader: (*|string), options: {}}|*|{loader: string, options})[]},{use: (string|{loader: string, options: {postcssOptions: {plugins: string[]}}}|{loader: (*|string), options: {}}|*|{loader: string, options})[]}]}
 */
const getStyleOneOfLoaders = (loader, options = {}, resourceOptions) => {
  const styleLoader = IS_PRO ? MiniCssExtractPlugin.loader : 'vue-style-loader'

  const postcssLoader = {
    loader: 'postcss-loader',
    options: {
      postcssOptions: {
        plugins: ['postcss-preset-env', 'autoprefixer']
      }
    }
  }

  const preLoader = loader && {
    loader: ~loader.indexOf('loader') ? loader : `${loader}-loader`,
    options: {
      ...options
    }
  }

  const sassResourcesLoader = loader &&
    resourceOptions && {
      loader: 'sass-resources-loader',
      options: {
        ...resourceOptions
      }
    }

  return [
    // 这里匹配 `<style module>`
    {
      resourceQuery: /module/,
      use: [
        styleLoader,
        'cache-loader',
        {
          loader: 'css-loader',
          options: {
            modules: true,
            localIdentName: '[local]_[fullhash:base64:5]'
          }
        },
        postcssLoader,
        preLoader,
        sassResourcesLoader
      ].filter(Boolean)
    },
    {
      use: [styleLoader, 'cache-loader', 'css-loader', postcssLoader, preLoader, sassResourcesLoader].filter(Boolean)
    }
  ]
}

/**
 * 获取ip
 * @returns {string}
 */
function getIPAddress() {
  const interfaces = os.networkInterfaces()
  for (const devName in interfaces) {
    const iface = interfaces[devName]
    for (let i = 0; i < iface.length; i++) {
      const alias = iface[i]
      if (alias.family === 'IPv4' && alias.address !== '127.0.0.1' && !alias.internal) {
        return alias.address
      }
    }
  }
}

/**
 * @param { Promise } promise
 * @param { Object } errorExt - 可以传递给err对象的其他信息
 * @return { Promise }
 * @description 对promise二次加工
 * @example
 * const [res, err] = awaitTo(api.xxxx)
 */
const asyncTo = (promise, errorExt = {}) => {
  return promise
    .then(function (data) {
      return [data, undefined]
    })
    .catch(function (err) {
      if (errorExt) {
        Object.assign(err, errorExt)
      }
      return [undefined, err]
    })
}

module.exports = {
  IS_PRO,
  ROOT_PATH,
  IS_DEV,
  SRC_PATH,
  getStyleOneOfLoaders,
  getStyleLoaders,
  getIPAddress,
  asyncTo
}
